package com.izhangqian.signproject.utils;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Environment;
import android.util.Log;

import com.izhangqian.pluginapk.PluginEntry;
import com.izhangqian.signproject.plugin.PluginApk;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import dalvik.system.DexClassLoader;

public class PluginManager {

    private static final String PLUGIN_FOLDER = "plugins";

    private Context mContext;
    private static PluginManager mInstance;
    private PluginManager(Context context) {
        mContext = context;
    }

    public static PluginManager getInstance(Context context) {
        if (mInstance == null) {
            synchronized (PluginManager.class) {
                mInstance = new PluginManager(context);
            }
        }
        return mInstance;
    }

    public List<PluginApk> getApks() {
        List<String> list = LoadUtils.getFilesFromLocal(mContext, mContext.getExternalFilesDir("") + File.separator + PLUGIN_FOLDER);
        List<String> allList = LoadUtils.getApksFromData(mContext);
        if (allList == null || allList.size() == 0) {
            return null;
        }
        List<PluginApk> apks = new ArrayList<>();
        for (String path : allList) {
            apks.add(getPlugin(path));
        }
        return apks;
    }

    public PluginApk getApk() {
        return getPlugin(LoadUtils.copyAssetAndWrite(mContext, "plugintest.apk"));
    }

    public PluginApk getPlugin(String apkPath) {
        File file = new File(apkPath);
        PackageInfo packageInfo = null;
        if (file.exists() && file.isFile()) {
            packageInfo = mContext.getPackageManager().getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
        }

        DexClassLoader classLoader = createClassLoader(apkPath);
        AssetManager assetManager = createAssetManager(apkPath);
        Resources resources = createResources(assetManager);
        Log.e("zqsapk", "no class found");
        PluginApk mApk = new PluginApk(classLoader, resources, packageInfo, assetManager);
        if (packageInfo != null) {
            try {
                Class cls = classLoader.loadClass(packageInfo.packageName + ".MyPluginEntryImpl");
                PluginEntry entry = (PluginEntry) cls.newInstance();
                mApk.setEntry(entry);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return mApk;
    }

    private Resources createResources(AssetManager assetManager) {
        Resources resources = mContext.getResources();
        return new Resources(assetManager, resources.getDisplayMetrics(), resources.getConfiguration());
    }

    private AssetManager createAssetManager(String apkPath) {
        try {
            AssetManager am = AssetManager.class.newInstance();
            Method method = AssetManager.class.getDeclaredMethod("addAssetPath", String.class);
            method.invoke(am, apkPath);
            return am;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private DexClassLoader createClassLoader(String apkPath) {
        File file = mContext.getDir("plugin", Context.MODE_PRIVATE);
        return new DexClassLoader(apkPath, file.getAbsolutePath(), null, mContext.getClassLoader());
    }
}
